#include "mainwindow.h"
#include "ui_mainwindow.h"

// SHEET
#include "multipagesheetwidget.h"

// APP FILE PROVIDER
#include "appfileprovider.h"

// DEBUG
#include <QDebug>

// FILE DIALOG
#include <QFileDialog>

// SETTINGS
#include <QSettings>

// MESSAGE BOX
#include <QMessageBox>

// PROCESS
#include <QProcess>

// PDF
#include "pdfhelper.h"

// PRIVATE SLOTS
WidgetWithGdrData* MainWindow::newCharacter()
{
    WidgetWithGdrData* sw = new MultiPageSheetWidget(this);
    sw->setGdrData(&gdrData);

    ui->tabWidget->addTab(sw, QIcon(), "John Doe");

    connect(sw->chModel(), SIGNAL(playerNameChanged(QString)), SLOT(onTabTitleChange(QString)));
    connect(sw->chModel(), SIGNAL(characterNameChanged(QString)), SLOT(onTabTitleChange(QString)));
    connect(sw->chModel(), SIGNAL(buildPointsChanged(int)), SLOT(updateStatusBar()));
    connect(sw->chModel(), SIGNAL(skillPointsChanged(int)), SLOT(updateStatusBar()));

    sw->chModel()->setProperty("PlayerName", "Me");
    sw->chModel()->setProperty("CharacterName", "John Doe");
    sw->chModel()->setProperty("BuildPoints", agBuildPoints->checkedAction()->data());
    sw->chModel()->setProperty("SkillPoints", agSkillPoints->checkedAction()->data());

    return sw;
}

void MainWindow::loadCharacterFromFile()
{
    QSettings settings;
    QString folder(settings.value("last_opensave_folder", QDir::homePath()).toString());
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Open Character"),
                                                    QDir::toNativeSeparators(folder),
                                                    tr("Character Files (*.json)"));

    if ( !fileName.isEmpty() )
    {
        settings.setValue("last_opensave_folder",
                          QFileInfo(fileName).absolutePath());
    }

    loadCharacterFromFile(fileName);
}

void MainWindow::loadCharacterFromFile(QString file)
{      
    MultiPageSheetWidget* sw = qobject_cast<MultiPageSheetWidget*>(newCharacter());

    connect(sw, SIGNAL(incompatibleDataLocale(QString,QString)), SLOT(showLocaleError(QString, QString)));
    connect(sw, SIGNAL(incompatibleDataVersion(QString,QString)), SLOT(showVersionError(QString, QString)));

    if ( sw->loadFrom(file) )
        sw->setProperty("SavedFileName", file);
    else
    {
        sw->deleteLater();
        int tab = ui->tabWidget->indexOf(sw);
        ui->tabWidget->removeTab(tab);
    }

    disconnect(this, SLOT(showLocaleError(QString, QString)));
    disconnect(this, SLOT(showVersionError(QString, QString)));
}

void MainWindow::saveCurrentCharacter()
{
    MultiPageSheetWidget* sw = qobject_cast<MultiPageSheetWidget*>(ui->tabWidget->currentWidget());
    if ( sw == 0 )
        return;

    QString fileName;
    if ( !sw->property("SavedFileName").isValid() )
    {
        //QFileDialog::setDefaultSuffix(".json");
        QSettings settings;
        QString folder(settings.value("last_opensave_folder", QDir::homePath()).toString());
        QString suggestedFile = QString("%1/%2.json")
                                .arg(folder)
                                .arg(sw->chModel()->property("CharacterName").toString());

        qDebug() << "Save suggested file: " << suggestedFile;

        fileName = QFileDialog::getSaveFileName(this,
                                                        tr("Save Character"),
                                                        QDir::toNativeSeparators(suggestedFile),
                                                        tr("Character Files (*.json)"));
        if ( !fileName.isEmpty() )
        {
            settings.setValue("last_opensave_folder",
                              QFileInfo(fileName).absolutePath());
        }
    }
    else
        fileName = sw->property("SavedFileName").toString();

    saveCurrentCharacter(fileName);

}

void MainWindow::saveCurrentCharacter(QString file)
{
    MultiPageSheetWidget* sw = qobject_cast<MultiPageSheetWidget*>(ui->tabWidget->currentWidget());
    if ( sw == 0 )
        return;

    sw->setProperty("SavedFileName", file);
    sw->saveTo(file);
}

void MainWindow::onTabTitleChange(QString value)
{
    Q_UNUSED(value)

    WidgetWithGdrData* sw = qobject_cast<WidgetWithGdrData*>(sender()->parent());

    if ( sw == 0 )
        return;

    QString title = QString("%1: %2")
            .arg(sender()->property("PlayerName").toString())
            .arg(sender()->property("CharacterName").toString());

    int tabIndex = ui->tabWidget->indexOf(sw);
    ui->tabWidget->setTabText(tabIndex, title);
}

void MainWindow::saveCurrentCharacterAs()
{
    WidgetWithGdrData* sw = qobject_cast<WidgetWithGdrData*>(ui->tabWidget->currentWidget());
    if ( sw == 0 )
        return;
    sw->setProperty("SavedFileName", QVariant());
    saveCurrentCharacter();
}

void MainWindow::onTabClosing(int tab)
{
    int res = QMessageBox::question(this,
                         tr("Trail of Cthulhu"),
                         tr("Be sure to save your changes before close the document.\nDo you want to close?"),
                         QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Cancel);

    if ( res == QMessageBox::Yes )
    {
        ui->tabWidget->widget(tab)->deleteLater();
        ui->tabWidget->removeTab(tab);
    }
}

void MainWindow::onTabChange(int tab)
{
    Q_UNUSED(tab)
    updateStatusBar();
}

void MainWindow::showLocaleError(QString chLocale, QString dataLocale)
{
    QString errStr = QString(tr("Could not load the character because it was created with different language settings.\n"
                                "Character language: %1\nApplication language: %2"))
            .arg(chLocale).arg(dataLocale);

    QMessageBox::critical(this,
                         tr("Trail of Cthulhu"),
                         errStr);
}

void MainWindow::showVersionError(QString chVersion, QString dataVersion)
{
    QString errStr = QString(tr("Could not load the character because it was created with a different version of this application.\n"
                                "Character version: %1\nApplication version: %2"))
            .arg(chVersion).arg(dataVersion);

    QMessageBox::critical(this,
                         tr("Trail of Cthulhu"),
                         errStr);
}

void MainWindow::exportAsPdfSheet()
{
    MultiPageSheetWidget* sw = qobject_cast<MultiPageSheetWidget*>(ui->tabWidget->currentWidget());
    if ( sw == 0 )
        return;

    QString fileName;
    if ( !sw->property("ExportPdfFile").isValid() )
    {
        QSettings settings;
        QString folder(settings.value("last_opensave_folder", QDir::homePath()).toString());
        QString suggestedFile = QString("%1/%2.pdf")
                                .arg(folder)
                                .arg(sw->chModel()->property("CharacterName").toString());

        qDebug() << "Export suggested file: " << suggestedFile;

        fileName = QFileDialog::getSaveFileName(this,
                                                        tr("Export PDF Character Sheet"),
                                                        QDir::toNativeSeparators(suggestedFile),
                                                        tr("PDF Files (*.pdf)"));
        if ( !fileName.isEmpty() )
        {
            settings.setValue("last_opensave_folder",
                              QFileInfo(fileName).absolutePath());
        }
    }
    else
        fileName = sw->property("ExportPdfFile").toString();

    exportAsPdfSheet(fileName);
}

void MainWindow::exportAsPdfSheet(QString pdfFilePath)
{
    MultiPageSheetWidget* sw = qobject_cast<MultiPageSheetWidget*>(ui->tabWidget->currentWidget());
    if ( sw == 0 )
        return;

    // CHECK PDFTK

    // GENERATE FORM FILL INFORMATION
    QString fdf_content = PdfHelper::generateFDF(sw->chModel());
    QString fdf_file_path = QDir::temp().absoluteFilePath("tocgen.fdf");

    // WRITE FDF FILE
    QFile fdf_file(fdf_file_path);
    if ( !fdf_file.open(QFile::WriteOnly | QFile::Truncate) )
        return;

    fdf_file.write(qPrintable(fdf_content), fdf_content.length());
    fdf_file.close();

    // GET FILLABLE SHEET
    QString fillable_sheet_path = AppFileProvider::getConfigFile("tocsheet_fillable.pdf");

    // CALL PDFTK
    QProcess* pdftk = new QProcess(this);
    connect(pdftk, SIGNAL(finished(int)), SLOT(onPdfSheetGenerated(int)));
    // AUTO DELETE ON FINISH
    connect(pdftk, SIGNAL(finished(int)), pdftk, SLOT(deleteLater()));

    QStringList args;
    args << fillable_sheet_path << "fill_form" << fdf_file_path << "output" << pdfFilePath << "flatten";

    pdftk->start("pdftk", args);

    sw->setProperty("ExportPdfFile", pdfFilePath);
}

void MainWindow::onPdfSheetGenerated(int returnValue)
{
    QMessageBox box;
    if ( returnValue == 0 )
    {
        box.information(this,
                        qApp->applicationName(),
                        tr("PDF Sheet created successfully"));
    }
    else
    {
        box.critical(this,
                     qApp->applicationName(),
                     tr("Could not create the PDF sheet."));
    }
}

void MainWindow::clearStatusBar()
{
    lbCharName->clear();
    lbCharPointTxt1->clear();
    lbCharPointTxt2->clear();
    lbCharPointVal1->clear();
    lbCharPointVal2->clear();
}

void MainWindow::updateStatusBar()
{
    WidgetWithGdrData* wg = qobject_cast<WidgetWithGdrData*>(ui->tabWidget->currentWidget());
    if ( wg == 0 )
    {
        clearStatusBar();
        return;
    }

    QObject* ch = wg->chModel();
    wg->updateData(ch); // TO BE SURE

    if ( ui->statusBar->children().count() == 2 )
    {
        // BUILD THE STATUS BAR
        ui->statusBar->addWidget( (lbCharName = new QLabel(this)) );
        ui->statusBar->addWidget( (lbCharPointTxt1 = new QLabel(this)) );
        ui->statusBar->addWidget( (lbCharPointVal1 = new QLabel(this)) );
        ui->statusBar->addWidget( (lbCharPointTxt2 = new QLabel(this)) );
        ui->statusBar->addWidget( (lbCharPointVal2 = new QLabel(this)) );
    }

    QString title = QString("%1: %2")
            .arg(ch->property("PlayerName").toString())
            .arg(ch->property("CharacterName").toString());

    lbCharName->setText(title);
    lbCharPointTxt1->setText(tr("Spent build points"));
    lbCharPointTxt2->setText(tr("Spent skill points"));

    lbCharPointVal1->setText(ch->property("SpentBp").toString());
    lbCharPointVal2->setText(ch->property("SpentSp").toString());
}

